﻿using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Aliphant.Tool.ExcelToJson.Helpers
{
    internal static class CommonHelper
    {
        public static List<string> GetExcelColumns(DataTable dataTable)
        {
            List<string> columNames = new List<string>();
            DataColumnCollection colums = dataTable.Columns;
            foreach (DataColumn item in colums)
            {
                columNames.Add(item.ColumnName);
            }
            return columNames;
        }

        public static void AddProperty(ExpandoObject exobj, string property, object value)
        {
            if (exobj == null) return;
            property = property.Trim();
            var dir = (IDictionary<string, object>)exobj;
            dir[property] = value;
        }

        public static bool IsEmptyRow(ExcelRange range)
        {
            int count = 0;
            foreach (var cell in range)
            {
                if (string.IsNullOrEmpty(range.ToString()))
                {
                    count++;
                }
            }

            return count == range.Count();
        }

        public static object ConvertValue(string parameter, string dataType)
        {
            DataType type = GetEnumByDescription<DataType>(dataType);
            return ConvertValue(parameter, type);
        }

        public static object ConvertValue(string parameter, DataType dataType)
        {
            if (string.IsNullOrEmpty(parameter))
            {
                return GetDefaultValue(dataType);
            }

            return dataType switch
            {
                DataType.String => parameter,
                DataType.Integer => ConvertToNumber(parameter),
                DataType.Bool => ConvertToBool(parameter),
                _ => parameter
            };
        }

        public static object GetDefaultValue(DataType dtype)
        {
            return dtype switch
            {
                DataType.String => string.Empty,
                DataType.Integer => 0,
                DataType.Bool => false,
                _ => string.Empty
            };
        }

        public static object ConvertToNumber(string value)
        {
            string hexPattern = @"^0x[0-9,a-f]+$";
            string intPattern = @"^-?\d+$";
            string floatPattern = @"^-?\d+.\d+$";

            if (Regex.IsMatch(value, intPattern, RegexOptions.IgnoreCase))
            {
                return Convert.ToInt32(value);
            }
            else if (Regex.IsMatch(value, hexPattern, RegexOptions.IgnoreCase))
            {
                return Convert.ToInt32(value, 16);
            }
            else if(Regex.IsMatch(value, floatPattern, RegexOptions.IgnoreCase))
            {
                return Convert.ToDouble(value);
            }
            else
            {
                return 0;
            }
        }

        public static bool ConvertToBool(string value)
        {
            if (value.ToLower() == "true")
            {
                return true;
            }
            else return false;
        }

        public static string GetPropertyName(string property)
        {
            string pattern = @" \$(Bool|Integer|String|Para)$";
            if (Regex.IsMatch(property, pattern, RegexOptions.IgnoreCase))
            {
                return property.Split('$')[0].Trim();
            }
            return property;
        }

        public static string GetPropertyType(string property)
        {
            string pattern = @" \$(Bool|Integer|String|Para)$";
            if (Regex.IsMatch(property, pattern, RegexOptions.IgnoreCase))
            {
                return property.Split('$')[1].Trim();
            }
            return string.Empty;
        }

        public static string GetArgumentType(string args)
        {
            string pattern = @"(Para|Args)\$.+";
            if (Regex.IsMatch(args, pattern, RegexOptions.IgnoreCase))
            {
                return args.Split('$')[0].Trim();
            }
            return args;
        }

        public static string GetDescription(Enum em)
        {
            FieldInfo? field = em.GetType().GetField(em.ToString());
            object[]? attrs = field?.GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (attrs == null || attrs.Length <= 0) return string.Empty;
            return ((DescriptionAttribute)attrs[0])?.Description ?? string.Empty;
        }

        public static T GetEnumByDescription<T>(string description) where T : Enum
        {
            foreach (var e in Enum.GetValues(typeof(T)))
            {
                object[] attrs = e.GetType().GetField(e.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (attrs == null || attrs.Length <= 0)
                {
                    throw new NullReferenceException();
                }
                var desc = (DescriptionAttribute)attrs[0];
                if (desc.Description == description) return (T)e;
            }

            throw new InvalidEnumArgumentException();
        }
    }
}
